# -*- coding: utf-8 -*-
from PodcastFeed import *
import traceback
import urllib
import httplib
import eyeD3

id3_ver = eyeD3.ID3_V2_3
podcast_file = os.path.expanduser('~') + '/.PodcastTagger/podcasts.ini'
globalProgress = 0

class AppURLopener(urllib.FancyURLopener):
	def __init__(self, *args):
		self.version = "PodcastTagger/0.01"
		urllib.FancyURLopener.__init__(self, *args)

urllib._urlopener = AppURLopener()

# Read the podcast configuration file, and return a dictionary with:
#	key = Local path to podcast files
#	value = dictionary containing the podcast's URL and any custom tags
def readPodcastFile(filename):
    """Read the podcast configuration file, and return a dictionary structure
     of the podcasts in that file. The structure is:
        key = Local path to podcast files
        value = dictionary containing the podcast's URL and any custom tags"""
    f = open(filename,"r")
    line = f.readline()
    CustomTags = {}
    path = ''
    d = {}
    while line != '':
        if line != '\n' and line[0] != '#':
            if line[0] == '[' and line[-2] == ']':
                if d.has_key('path'):
                    path = d['path']
                    del(d['path'])
                    CustomTags[path] = d
                    d = {}
            else:
                l = line.split('=',1)
                if (len(l) > 1):
                    l[1] = l[1][:-1]
                    d[l[0]] = l[1]
        line = f.readline()
    if d.has_key('path'):
        path = d['path']
        if path[-1] == '/':
            path = path[:-1]
        del(d['path'])
        CustomTags[path] = d
        d = {}
    f.close()
    return CustomTags

def GetPodcastFeed(path,info):
    ptlogger.info('Podcast \"%s\"',path.split('/').pop())
    try:
        if os.path.exists(path) and info.has_key('url'):
            p = PodcastFeed(path,info['url'])
            if info.has_key('date_format_out'):
                    p.date_format_out = info['date_format_out']
            p.read()
            ptlogger.debug('Got Feed')
        else:
            ptlogger.error('Path does not exist: \"%s\"',path)
    except IOError, e:
        ptlogger.error('Timeout. Continuing.')
        return None
    return p

# Load the podcast file, download all feeds, and get a list of every podcast
# item found.
def getAllPodcasts(pfile):
    t = []
    ptlogger.info('Getting Podcasts List')
    podcasts = readPodcastFile(pfile)
    for path,info in podcasts.iteritems():
        p = GetPodcastFeed(path,info)
        if p != None:
            t.append(p)
    ptlogger.info('Got All Feeds')
    return t

# Convenience function to get all podcast items from the current podcast file
def getAll():
    return getAllPodcasts(podcast_file)

# Take a list of items pulled from the podcast feeds and compare them to local podcast files.
# Return a list of any changes that need to be made in those files' tags. Format is:
#	changes[<index>] = [<podcast file path>, {<tag1> : <tag value1>, <tag2> : <tag value2>,...}]
def CompareToTags(podcasts):
    tag = eyeD3.Tag()
    changes = {}
    CustomTags = readPodcastFile(podcast_file)
    n = 0
    for podcast in podcasts:
        n = n + len(podcast.items)
    ptlogger.debug('%d Items to check',n)
    i = 0
    for podcast in podcasts:
        ct = None
        if CustomTags.has_key(podcast.path):
            ct = CustomTags[podcast.path]
            if ct.has_key('album'):
                podcast.title = ct['album']
            if ct.has_key('author'):
                podcast.author = ct['author']
        if ct != None and podcast != None:
            changes[podcast.title] = {}
        for item in podcast.items:
            if not(eyeD3.isMp3File(item[0])):
                continue
            if ct != None and ct.has_key('title'):
                tm = ct['title']
                tm = tm.replace('%{pubDate}',item[2])
                tm = tm.replace('%{title}',item[1])
                item[1] = tm
            try:
                tag.link(item[0])
                title = tag.getTitle()
                album = tag.getAlbum()
                author = tag.getArtist()
                if tag.getGenre() == None:
                    genre = ''
                else:
                    genre = tag.getGenre().getName()
            except eyeD3.tag.TagException:
                ptlogger.error('Tag Exception on file \"%s\"',item[0])
                continue
            except eyeD3.tag.GenreException:
                genre = ''
            d = {}
            try:
                if album != podcast.title and podcast.title != "":
                    d['album'] = podcast.title
                if title != str(item[1]) and str(item[1]) != "":
                    d['title'] = item[1]
                if author != podcast.author and podcast.author != '':
                    d['author'] = podcast.author
                if genre != 'Podcast':
                    d['genre'] = 'Podcast'
                if d != {}:
                    changes[podcast.title][item[0]] = d
            except UnicodeEncodeError:
                ptlogger.error('Unicode Encode Error on file \"%s\"',item[0])
                continue
            i = i + 1
            globalProgress = int(round(100 * float(i) / float(n)))
            ptlogger.debug('i = %d; n = %d, globalProgress = %d',i,n,globalProgress)
    return changes

# Apply a change to a podcast file.
def ApplyChange(change):
    ptlogger.info('file \"%s\"',change[0].split('/')[-1])
    tag = eyeD3.Tag()
    if eyeD3.isMp3File(change[0]):
        try:
            tag.link(change[0])
            if tag.getVersion() == None:
                ptlogger.info('File \"%s\" has no ID3 tag version information. Fixing.',change[0].split('/')[-1])
                tag.setVersion(id3_ver)
                tag.setTitle("Temp")
                tag.update()
            UpdateFuncs = [['title',tag.getTitle,tag.setTitle],
                            ['album',tag.getAlbum,tag.setAlbum],
                            ['author',tag.getArtist,tag.setArtist],
                            ['genre',tag.getGenre,tag.setGenre]]
            changed = False
            for u in UpdateFuncs:
                try:
                    ptlogger.info('\t%s is \"%s\"',u[0],u[1]())
                except:
                    ptlogger.info('Couldn\'t log info')
                if change[1].has_key(u[0]):
                    try:
                        ptlogger.info('\tSet %s to \"%s\"',u[0],change[1][u[0]])
                    except:
                        ptlogger.info('Couldn\'t log info')
                    u[2](change[1][u[0]])
                    changed = True
            if changed:
                ptlogger.info("\tSave Changes")
                tag.update(id3_ver)
        except eyeD3.tag.TagException, e:
            ptlogger.error('Tag Exception on file \"%s\": %s',change[0],str(e))
        except ValueError, e:
            ptlogger.error('Value Error on file \"%s\": %s',change[0],str(e))

# Apply all changes to podcast files.
def ApplyChanges(changes):
    for p,c in changes.iteritems():
        for f,t in c.iteritems():
            ApplyChange([f,t])
    ptlogger.debug('All Podcast Tags Updated')

# Convenience method to get all current changes to all local podcast files.
def getAllChanges():
    return CompareToTags(getAll())
